/* -*- mode: c++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */

#ifndef _STRHELPER_H_
#define _STRHELPER_H_

#include <string>
#include <vector>

#define CHAR_IS_LOWER(c)                        \
    ((c) >= 'a' && (c) <= 'z')

#define CHAR_IS_UPPER(c)                        \
    ((c) >= 'A' && (c) <= 'Z')

#define CHAR_UPPER(c)                                       \
    (CHAR_IS_LOWER(c) ? ((c) - 'a' + 'A') : (c))

#define CHAR_IS_DIG(c)                          \
    ((c) >= '0' && (c) <= '9')

#define CHAR_LOWER(c)                                       \
    (CHAR_IS_UPPER(c) ? ((c) - 'A' + 'a') : (c))

#define CHAR_IS_WS(c)                                   \
    (c == ' ' || c == '\t' || c == '\n' || c == '\r')

#define SKIP_HEADING_SPACE(ptr)                 \
    do {                                        \
        while (*ptr) {                          \
            if (CHAR_IS_WS(*ptr))               \
                ++ptr;                          \
            else                                \
                break;                          \
        }                                       \
    } while (0)

#define SKIP_BEGINNING(ptr, cmp, ok)            \
    do {                                        \
        if (strstr(ptr, cmp) == ptr) {          \
            ptr += strlen(cmp);                 \
            ok = true;                          \
        }                                       \
        else                                    \
            ok = false;                         \
    } while (0)

#define SKIP_AND_PARSE_INT(ptr, res)                \
    do {                                            \
        res = 0;                                    \
        while ((char c = *ptr) && CHAR_IS_DIG(c)) { \
            res *= 10;                              \
            res += c - '0';                         \
            ++ptr;                                  \
        }                                           \
    } while (0)

#ifdef WIN32
#define __attribute__(x) /* nothing in win32 */

#define strcasecmp stricmp
#endif

extern bool
str_begin_with_no_case(const char *str,
                       const char *cmp);

extern void *
str_find_char_no_case(const char *str,
                      char        c);

extern int
str_find_no_case(const char *str,
                 const char *cmp);

extern char
str_next_char_no_space(const char *str);

extern char *
str_next_char_except(const char *p,
                     const char *exps);

extern char *
str_find_char_unless(const char *p, char c,
                     const char *exps);

extern char *
str_get_fn_nondir(const char *path);

extern void str_rtrim(char *p);

extern void str_ltrim(char *p);

extern void str_lrtrim(char *p);

extern void str_rtrim(std::string& s);

extern void str_ltrim(std::string& s);

extern void str_lrtrim(std::string& s);

extern int
str_get_str_until(char  *p,   char spec,
                  char  *buf, int bufsiz,
                  char **end);

extern int
str_get_str_until(char *p, char spec,
                  std::string& r, char **end);

extern int
str_get_escape_str_until(char  *p,   char spec,
                         char  *buf, int  bufsiz,
                         char **end);

extern int
str_get_escape_str_until(char  *p, char spec,
                         std::string& r, char **end);

extern void
str_get_suffix(const char *s, std::string& suffix);

extern void
str_lower(std::string& s);

extern void
str_upper(std::string& s);

extern void
str_lower(char *s);

extern void
str_upper(char *s);

extern bool
str_suffix_is(const char *s, const char *suffix);

extern void
str_append(std::string& r, int i);

extern int
str_format(std::string& r, const char *fmt, ...)
    __attribute__((format(printf, 2, 3)));

extern int
str_format_append(std::string& r, const char *fmt, ...)
    __attribute__((format(printf, 2, 3)));

extern int
str_parse_int(char *p, int *r, char **end);

extern int
str_get_dir(const char *p, std::string& r);

extern void
str_no_suffix(const char *name, std::string& r);

extern int
str_get_char_cnt(const char *str, char c);

extern int
str_get_char_cnt(const char *str, int len, char c);

extern void
str_to_hex(const void *p, int len, std::string& res);

extern void str_to_printable(const void   *p,
                             int           len,
                             std::string&  res,
                             char          replace = '?');

extern void str_to_printable_hex(const void   *p,
                                 int           len,
                                 std::string&  res);

extern bool
str_is_all_hex(const char *str, int len);

int
str_hex_to_bytes_not_check(const char *str, int len, char *out);

extern char *
str_dup(const char *str, int len = 0);

extern void
str_replace_char(char *str, char from, char to);

extern int
str_split_by_chars(const char                *src,
                   const char                *seps,
                   std::vector<std::string>&  res);

#endif /* _STRHELPER_H_ */
